package com.haiyou.data.common.persister.mysql.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.haiyou.common.util.date.DateUtils;
import com.haiyou.common.util.string.StringUtils;


/**
 * 数据表,mysql要求所有列字符长度加起来乘以2（gbk）或者是3(utf-8).
 * 如果这个结果大于65535，是无法创建成功的。所以如果字段是String，只有被设置为主键或者索引才会使用char、varchar，
 * 否则一律使用tinytext/text...
 * 
 * @author xingyuan
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
@Documented
public @interface Table {

	/**
	 * 是否在自动修复表结构时允许删除字段
	 * 
	 * @return
	 */
	boolean columnDropable() default false;
	
	/**
	 * 可能是视图
	 * @return
	 */
	boolean view() default false;

	/**
	 * 表名称，必须小写，如果分表数据大于1或者是滚表类型不是NONE那么表名会被加上分表编号或者日期
	 * </p>
	 * 
	 * @return
	 */
	String name() default "";

	/**
	 * 描述
	 * 
	 * @return
	 */
	Comment comment() default @Comment();

	/**
	 * 是否继承父类的字段属性并且持久化到自己的表中
	 * 
	 * @return
	 */
	boolean mappedSuperclass() default true;

	/**
	 * 不可以与roll共存，分表数量，默认是1不分表，先对数据量做出预估，如果超过500万条，建议分表，
	 * 
	 * @return
	 */
	int cluster() default 1;

	/**
	 * 不可以与cluster共存，按日期滚表策略，通常只有日志需要这么干，比如以每周生成一张新表来保存日志，也就是每年54张表
	 * 
	 * @return
	 */
	RollPolicy rollPolicy() default RollPolicy.NONE;

	/**
	 * sql每一批执行条数，如果sql过长会导致Packet for query is too large 异常
	 * </pre>
	 * show VARIABLES like '%max_allowed_packet%' | 查询mysql使用的配置
	 * 
	 * <pre>
	 * set max_allowed_packet =524288000 | 500M 修改mysql Server 接受的数据包大小
	 * </pre>
	 * 
	 * max_allowed_packet =524288000 | 500M 修改my.ini [mysqld]配置
	 * </pre>
	 * 
	 */
	int sqlBatchNum() default 1000;

	/** 索引 */
	Index[] indexes() default {};

	/**
	 * 滚库/表策略,不能和分库/表策略同时存在，只能二选一
	 * 
	 * @author jason
	 */
	enum RollPolicy {

		/** 不滚动生成库/表，也就是单库/表 */
		NONE(null), //
		/** 每小时生成一张新库/表 */
		EVERY_HOUR("yyyyMMddHH"), //
		/** 每天生成一张新库/表，注意如果那天没有任何日志数据产生是不会生成新库/表的 */
		EVERY_DAY("yyyyMMdd"), //
		/** 每月生成一张新库/表 */
		EVERY_MONTH("yyyyMM"), //
		/** 每年生成一张新库/表 */
		EVERY_YEAR("yyyy"), //
		
		/** 按月每周生成一张新库/表 */
		EVERY_WEEK_OF_MONTH("yyyyMM"), //
		/** 按年每周生成一张新库/表 */
		EVERY_WEEK_OF_YEAR("yyyy"), //
		;

		public final String format;

		private RollPolicy(String format) {
			this.format = format;
		}

		/**
		 * 滚库/表名称前缀 @see {@link RollPolicy}
		 */
		public static final String PREFIX = "@";

		/** 拼接后缀 */
		public static String suffix(RollPolicy rollPolicy, long t) {
			SimpleDateFormat formatter = new SimpleDateFormat(rollPolicy.format);
			switch (rollPolicy) {
			case EVERY_HOUR:
			case EVERY_DAY:
			case EVERY_MONTH:
			case EVERY_YEAR:
				return formatter.format(new Date(t));
			case EVERY_WEEK_OF_MONTH:
			case EVERY_WEEK_OF_YEAR:
				int weekIndex = rollPolicy == EVERY_WEEK_OF_MONTH ? DateUtils.weekOfMonth(t) : DateUtils.weekOfYear(t);
				String dateStr = formatter.format(new Date(t));
				return dateStr + (weekIndex < 10 ? (0 + "" + weekIndex) : weekIndex);
			default:
				throw new RuntimeException("suffix unknown roll[" + rollPolicy + "]");
			}
		}

		public static String fixName(String name, RollPolicy rollPolicy) {
			if (rollPolicy == NONE)
				return name;
			return parseName(name, rollPolicy, System.currentTimeMillis());
		}

		public static String parseName(String name, RollPolicy rollPolicy, long t) {
			if (rollPolicy == NONE)
				return name;
			return StringUtils.mergeJoiner("_", PREFIX, name, suffix(rollPolicy, t));
		}

	}

}
